package com.yqb.study.common.session;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import com.yqb.study.common.bean.SpringContextHolder;
import com.yqb.study.common.exception.GlobalException;
import com.yqb.study.common.session.args.RedisSession;
import com.yqb.study.constant.CodeMsgEnum;
import com.yqb.study.constant.key.ICookieKey;
import com.yqb.study.constant.key.redis.RedisSessionKey;
import com.yqb.study.modular.persistence.model.User;
import com.yqb.study.util.CookieUtil;
import com.yqb.study.util.FastJsonUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RedisSessionImpl implements IRedisSession {

	private RedisSession sessionRedis = null;

	private RedisTemplate redisTemplate = null;
	
	public RedisSessionImpl(String token) {
		// log.info("新建SessionRedisImpl");
		
		redisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);
		
		getSessionRedis(token);
	}

	@Override
	public RedisSession getSessionRedis() {
		return this.sessionRedis;
	}

	@Override
	public RedisSession getSessionRedis(String token) {
		ValueOperations<String, String> redisOperations = redisTemplate.opsForValue();
		String sessionRedisStr = redisOperations.get(RedisSessionKey.sessionToken.getPrefix() + token);
		this.sessionRedis = FastJsonUtil.jsonToObject(sessionRedisStr, RedisSession.class);

		return this.sessionRedis;
	}

	@Override
	public Object getFromSessionRedis(String name) {
		RedisSession sessionRedis = this.sessionRedis;
		if (sessionRedis == null) {
			throw new GlobalException(CodeMsgEnum.SESSION_ERROR);
		}

		if (StringUtils.isEmpty(name)) {
			return null;
		}

		Map<String, Object> para = sessionRedis.getPara();
		if (para == null || !para.containsKey(name)) {
			return null;
		}

		return para.get(name);
	}

	@Override
	public void putInSessionRedis(String name, Object value) {
		RedisSession sessionRedis = this.sessionRedis;
		if (sessionRedis == null) {
			throw new GlobalException(CodeMsgEnum.SESSION_ERROR);
		}

		Map<String, Object> para = sessionRedis.getPara();
		if (para == null) {
			sessionRedis.setPara(new HashMap<>());
		}
		sessionRedis.getPara().put(name, value);

		ValueOperations<String, String> redisOperations = redisTemplate.opsForValue();
		if (RedisSessionKey.EXPIRE_TIME <= 0) {
			redisOperations.set(RedisSessionKey.sessionToken.getPrefix() + sessionRedis.getToken(),
					FastJsonUtil.toJson(sessionRedis));
		} else {
			redisOperations.set(RedisSessionKey.sessionToken.getPrefix() + sessionRedis.getToken(),
					FastJsonUtil.toJson(sessionRedis), RedisSessionKey.EXPIRE_TIME, TimeUnit.SECONDS);
		}
	}

	@Override
	public void addCookieSession(HttpServletResponse response, String token, User user) {

		if (this.sessionRedis == null) {
			this.sessionRedis = new RedisSession();
		}
		RedisSession sessionRedis = this.sessionRedis;

		sessionRedis.setToken(token);
		sessionRedis.setUser(user);

		// 1.登录成功，设置token对应user至redis
		ValueOperations<String, String> redisOperations = redisTemplate.opsForValue();
		if (RedisSessionKey.EXPIRE_TIME <= 0) {
			redisOperations.set(RedisSessionKey.sessionToken.getPrefix() + sessionRedis.getToken(),
					FastJsonUtil.toJson(sessionRedis));
		} else {
			redisOperations.set(RedisSessionKey.sessionToken.getPrefix() + sessionRedis.getToken(),
					FastJsonUtil.toJson(sessionRedis), RedisSessionKey.EXPIRE_TIME, TimeUnit.SECONDS);
		}

		// 2.登录成功，设置token至cookie
		CookieUtil.set(response, ICookieKey.TOKEN_KEY, token, RedisSessionKey.sessionToken.expireSeconds());
	}

	@Override
	public void clearCookieSession(HttpServletResponse response, String token) {
		// 1.清除redis
		redisTemplate.delete(RedisSessionKey.sessionToken.getPrefix() + token);

		// 2.清除cookie
		CookieUtil.set(response, ICookieKey.TOKEN_KEY, null, 0);

		this.sessionRedis = null;
	}

}
